package com.web3.management.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.web3.management.dto.PageResponse;
import com.web3.management.dto.request.CreateAccountConfigRequest;
import com.web3.management.dto.response.AccountConfigDetailResponse;
import com.web3.management.dto.response.AccountConfigHistoryResponse;
import com.web3.management.dto.response.AccountConfigListResponse;
import com.web3.management.dto.response.EffectiveConfigResponse;
import com.web3.management.entity.Account;
import com.web3.management.entity.AccountConfig;
import com.web3.management.entity.AccountConfigHistory;
import com.web3.management.entity.Config;
import com.web3.management.exception.BusinessException;
import com.web3.management.repository.AccountConfigHistoryRepository;
import com.web3.management.repository.AccountConfigRepository;
import com.web3.management.repository.AccountRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 账号配置服务类
 *
 * @author Web3 Management Team
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AccountConfigService {

    private final AccountConfigRepository accountConfigRepository;
    private final AccountConfigHistoryRepository accountConfigHistoryRepository;
    private final AccountRepository accountRepository;
    private final AccountService accountService;
    private final ConfigService configService;
    private final OperationLogService operationLogService;
    private final ObjectMapper objectMapper;

    /**
     * 分页查询账号配置
     */
    public PageResponse<AccountConfigListResponse> getAccountConfigs(Integer accountId, Integer page, Integer size, Integer status) {
        // 验证账号是否存在
        Account account = accountService.getById(accountId);
        if (account == null) {
            throw new BusinessException("账号不存在");
        }

        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "updatedAt"));
        Page<AccountConfig> configPage;

        if (status != null) {
            configPage = accountConfigRepository.findByAccountIdAndStatus(accountId, status, pageable);
        } else {
            configPage = accountConfigRepository.findByAccountId(accountId, pageable);
        }

        List<AccountConfigListResponse> responseList = configPage.getContent().stream()
                .map(this::convertToListResponse)
                .collect(Collectors.toList());

        return PageResponse.of(configPage.getTotalElements(), page, size, responseList);
    }

    /**
     * 获取账号配置详情
     */
    public AccountConfigDetailResponse getAccountConfigDetail(Integer accountId, Integer configId) {
        AccountConfig config = getByAccountIdAndId(accountId, configId);
        return convertToDetailResponse(config);
    }

    /**
     * 创建账号配置
     */
    @Transactional
    public AccountConfig createAccountConfig(Integer accountId, CreateAccountConfigRequest request) {
        // 验证账号是否存在
        Account account = accountService.getById(accountId);
        if (account == null) {
            throw new BusinessException("账号不存在");
        }

        // 检查配置名称是否已存在
        if (accountConfigRepository.existsByAccountIdAndConfigName(accountId, request.getConfigName())) {
            throw new BusinessException("该账号下已存在同名配置");
        }

        // 验证自定义配置JSON格式
        if (StringUtils.hasText(request.getCustomConfig())) {
            try {
                objectMapper.readTree(request.getCustomConfig());
            } catch (Exception e) {
                throw new BusinessException("自定义配置JSON格式不正确");
            }
        }

        // 创建账号配置
        AccountConfig config = new AccountConfig();
        config.setAccountId(accountId);
        config.setConfigName(request.getConfigName());
        config.setProjectName(request.getProjectName());
        config.setBaseAsset(request.getBaseAsset());
        config.setQuoteAsset(request.getQuoteAsset());
        config.setChainId(request.getChainId());
        config.setContractAddress(request.getContractAddress());
        config.setBuyAmount(request.getBuyAmount() != null ? request.getBuyAmount() : BigDecimal.ZERO);
        config.setTargetBuyQuote(request.getTargetBuyQuote() != null ? request.getTargetBuyQuote() : BigDecimal.ZERO);
        config.setProxyEnabled(request.getProxyEnabled() != null && request.getProxyEnabled() ? 1 : 0);
        config.setProxyConfig(request.getProxyConfig());
        config.setNotifyUrl(request.getNotifyUrl());
        config.setCustomConfig(request.getCustomConfig());
        config.setRemark(request.getRemark());
        config.setIsActive(0);
        config.setStatus(1);

        AccountConfig savedConfig = accountConfigRepository.save(config);
        String newConfigJson = serializeAccountConfig(savedConfig);
        recordAccountConfigHistory(savedConfig.getId(), "{}", newConfigJson, "创建账号配置", "CREATE");
        operationLogService.record("CREATE_ACCOUNT_CONFIG", "ACCOUNT_CONFIG", savedConfig.getId(),
                String.format("账号 %s 创建配置 %s", account.getName(), savedConfig.getConfigName()));
        log.info("创建账号配置成功: accountId={}, configName={}", accountId, request.getConfigName());

        return savedConfig;
    }

    /**
     * 更新账号配置
     */
    @Transactional
    public AccountConfig updateAccountConfig(Integer accountId, Integer configId, CreateAccountConfigRequest request) {
        AccountConfig config = getByAccountIdAndId(accountId, configId);

        // 检查配置名称是否与其他配置冲突
        if (!config.getConfigName().equals(request.getConfigName()) &&
                accountConfigRepository.existsByAccountIdAndConfigNameAndIdNot(accountId, request.getConfigName(), configId)) {
            throw new BusinessException("该账号下已存在同名配置");
        }

        // 验证自定义配置JSON格式
        if (StringUtils.hasText(request.getCustomConfig())) {
            try {
                objectMapper.readTree(request.getCustomConfig());
            } catch (Exception e) {
                throw new BusinessException("自定义配置JSON格式不正确");
            }
        }

        String oldConfigJson = serializeAccountConfig(config);

        // 更新配置
        config.setConfigName(request.getConfigName());
        config.setProjectName(request.getProjectName());
        config.setBaseAsset(request.getBaseAsset());
        config.setQuoteAsset(request.getQuoteAsset());
        config.setChainId(request.getChainId());
        config.setContractAddress(request.getContractAddress());
        config.setBuyAmount(request.getBuyAmount() != null ? request.getBuyAmount() : BigDecimal.ZERO);
        config.setTargetBuyQuote(request.getTargetBuyQuote() != null ? request.getTargetBuyQuote() : BigDecimal.ZERO);
        config.setProxyEnabled(request.getProxyEnabled() != null && request.getProxyEnabled() ? 1 : 0);
        config.setProxyConfig(request.getProxyConfig());
        config.setNotifyUrl(request.getNotifyUrl());
        config.setCustomConfig(request.getCustomConfig());
        config.setRemark(request.getRemark());

        AccountConfig savedConfig = accountConfigRepository.save(config);
        String newConfigJson = serializeAccountConfig(savedConfig);
        recordAccountConfigHistory(savedConfig.getId(), oldConfigJson, newConfigJson, "更新账号配置", "UPDATE");
        operationLogService.record("UPDATE_ACCOUNT_CONFIG", "ACCOUNT_CONFIG", savedConfig.getId(),
                String.format("账号 %d 更新配置 %s", accountId, savedConfig.getConfigName()));
        log.info("更新账号配置成功: accountId={}, configId={}", accountId, configId);

        return savedConfig;
    }

    /**
     * 激活账号配置
     */
    @Transactional
    public void activateAccountConfig(Integer accountId, Integer configId) {
        // 验证配置是否存在
        AccountConfig config = getByAccountIdAndId(accountId, configId);

        // 停用该账号的所有配置，然后激活指定配置
        accountConfigRepository.activateAccountConfigAndDeactivateOthers(accountId, configId);

        // 激活配置时，设置账号需要重启标志
        Account account = accountService.getById(accountId);
        account.setNeedsRestart(true);
        accountRepository.save(account);

        operationLogService.record("ACTIVATE_ACCOUNT_CONFIG", "ACCOUNT_CONFIG", configId,
                String.format("账号 %d 激活配置 %s", accountId, config.getConfigName()));
        log.info("激活账号配置成功: accountId={}, configId={}", accountId, configId);
    }

    /**
     * 删除账号配置
     */
    @Transactional
    public void deleteAccountConfig(Integer accountId, Integer configId) {
        AccountConfig config = getByAccountIdAndId(accountId, configId);
        String oldConfigJson = serializeAccountConfig(config);
        accountConfigRepository.delete(config);
        recordAccountConfigHistory(configId, oldConfigJson, "{}", "删除账号配置", "DELETE");
        operationLogService.record("DELETE_ACCOUNT_CONFIG", "ACCOUNT_CONFIG", configId,
                String.format("账号 %d 删除配置 %s", accountId, config.getConfigName()));
        log.info("删除账号配置成功: accountId={}, configId={}", accountId, configId);
    }

    /**
     * 获取账号有效配置（合并全局配置）
     */
    public EffectiveConfigResponse getEffectiveConfig(Integer accountId) {
        // 验证账号是否存在
        Account account = accountService.getById(accountId);
        if (account == null) {
            throw new BusinessException("账号不存在");
        }

        // 获取账号激活配置
        AccountConfig accountConfig = accountConfigRepository
                .findByAccountIdAndIsActive(accountId, 1)
                .orElse(null);

        // 获取全局激活配置作为fallback
        Config globalConfig = configService.getActiveConfig();

        // 构建响应
        EffectiveConfigResponse response = new EffectiveConfigResponse();
        response.setHasAccountConfig(accountConfig != null);

        if (accountConfig != null) {
            response.setActiveAccountConfig(convertToDetailResponse(accountConfig));
        }

        if (globalConfig != null) {
            try {
                JsonNode globalJson = objectMapper.readTree(globalConfig.getConfigContent());
                Map<String, Object> globalMap = objectMapper.convertValue(globalJson, new TypeReference<Map<String, Object>>() {});
                response.setGlobalFallback(globalMap);
            } catch (Exception e) {
                log.warn("解析全局配置JSON失败: {}", e.getMessage());
            }
        }

        // 合并配置
        response.setEffectiveConfig(mergeConfigs(accountConfig, globalConfig));

        return response;
    }

    /**
     * 获取账号配置历史记录
     */
    public PageResponse<AccountConfigHistoryResponse> getAccountConfigHistory(Integer accountId,
                                                                              Integer configId,
                                                                              Integer page,
                                                                              Integer size) {
        AccountConfig config = getByAccountIdAndId(accountId, configId);
        PageRequest pageRequest = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        Page<AccountConfigHistory> historyPage = accountConfigHistoryRepository
                .findByAccountConfigIdOrderByCreatedAtDesc(config.getId(), pageRequest);

        List<AccountConfigHistoryResponse> list = historyPage.getContent().stream()
                .map(this::convertToHistoryResponse)
                .collect(Collectors.toList());

        return PageResponse.of(historyPage.getTotalElements(), page, size, list);
    }

    /**
     * 从全局配置创建账号配置
     */
    @Transactional
    public AccountConfig createFromGlobalConfig(Integer accountId, Integer globalConfigId, String configName, Map<String, Object> overrides) {
        // 验证账号是否存在
        Account account = accountService.getById(accountId);
        if (account == null) {
            throw new BusinessException("账号不存在");
        }

        // 获取全局配置
        Config globalConfig = configService.getById(globalConfigId);
        if (globalConfig == null) {
            throw new BusinessException("全局配置不存在");
        }

        // 检查配置名称是否已存在
        if (accountConfigRepository.existsByAccountIdAndConfigName(accountId, configName)) {
            throw new BusinessException("该账号下已存在同名配置");
        }

        // 解析全局配置
        try {
            JsonNode globalJson = objectMapper.readTree(globalConfig.getConfigContent());

            // 创建账号配置
            AccountConfig config = new AccountConfig();
            config.setAccountId(accountId);
            config.setConfigName(configName);
            config.setProjectName(globalJson.path("name").asText());
            config.setBaseAsset(globalJson.path("baseAsset").asText());
            config.setQuoteAsset(globalJson.path("quoteAsset").asText());
            config.setChainId(globalJson.path("chainId").asInt());
            config.setContractAddress(globalJson.path("contractAddress").asText());
            config.setBuyAmount(BigDecimal.valueOf(globalJson.path("buyAmount").asDouble()));
            config.setTargetBuyQuote(BigDecimal.valueOf(globalJson.path("targetBuyQuote").asDouble()));
            config.setProxyEnabled(globalJson.path("proxy").asBoolean() ? 1 : 0);
            config.setNotifyUrl(globalJson.path("notifyUrl").asText());

            // 应用覆盖配置
            if (overrides != null) {
                applyOverrides(config, overrides);
            }

            config.setIsActive(0);
            config.setStatus(1);
            config.setRemark("基于全局配置 [" + globalConfig.getName() + "] 创建");

            AccountConfig savedConfig = accountConfigRepository.save(config);
            String newConfigJson = serializeAccountConfig(savedConfig);
            recordAccountConfigHistory(savedConfig.getId(), "{}", newConfigJson,
                    "从全局配置创建账号配置", "CREATE");
            operationLogService.record("CREATE_ACCOUNT_CONFIG", "ACCOUNT_CONFIG", savedConfig.getId(),
                    String.format("账号 %d 基于全局配置 %s 创建配置 %s", accountId, globalConfig.getName(), savedConfig.getConfigName()));
            log.info("从全局配置创建账号配置成功: accountId={}, globalConfigId={}", accountId, globalConfigId);

            return savedConfig;
        } catch (Exception e) {
            log.error("从全局配置创建账号配置失败: {}", e.getMessage());
            throw new BusinessException("创建配置失败: " + e.getMessage());
        }
    }

    /**
     * 检查账号是否有配置
     */
    public boolean hasAccountConfig(Integer accountId) {
        return accountConfigRepository.existsByAccountId(accountId);
    }

    /**
     * 根据账号ID和配置ID获取配置
     */
    private AccountConfig getByAccountIdAndId(Integer accountId, Integer configId) {
        return accountConfigRepository.findById(configId)
                .filter(config -> config.getAccountId().equals(accountId))
                .orElseThrow(() -> new BusinessException("账号配置不存在"));
    }

    /**
     * 合并配置（账号配置优先，全局配置作为fallback）
     */
    private Map<String, Object> mergeConfigs(AccountConfig accountConfig, Config globalConfig) {
        Map<String, Object> merged = new HashMap<>();

        // 先使用全局配置
        if (globalConfig != null) {
            try {
                JsonNode globalJson = objectMapper.readTree(globalConfig.getConfigContent());
                Map<String, Object> globalMap = objectMapper.convertValue(globalJson, new TypeReference<Map<String, Object>>() {});
                merged.putAll(globalMap);
            } catch (Exception e) {
                log.warn("解析全局配置失败: {}", e.getMessage());
            }
        }

        // 账号配置覆盖全局配置
        if (accountConfig != null) {
            merged.put("name", accountConfig.getProjectName());
            merged.put("baseAsset", accountConfig.getBaseAsset());
            merged.put("quoteAsset", accountConfig.getQuoteAsset());
            merged.put("chainId", accountConfig.getChainId());
            merged.put("contractAddress", accountConfig.getContractAddress());
            merged.put("buyAmount", accountConfig.getBuyAmount());
            merged.put("targetBuyQuote", accountConfig.getTargetBuyQuote());
            merged.put("proxy", accountConfig.getProxyEnabled() == 1);
            merged.put("notifyUrl", accountConfig.getNotifyUrl());

            // 合并自定义配置
            if (StringUtils.hasText(accountConfig.getCustomConfig())) {
                try {
                    JsonNode customConfigJson = objectMapper.readTree(accountConfig.getCustomConfig());
                    Map<String, Object> customConfigMap = objectMapper.convertValue(customConfigJson, new TypeReference<Map<String, Object>>() {});
                    merged.putAll(customConfigMap);
                } catch (Exception e) {
                    log.warn("解析自定义配置失败: {}", e.getMessage());
                }
            }
        }

        return merged;
    }

    private String serializeAccountConfig(AccountConfig config) {
        if (config == null) {
            return "{}";
        }
        try {
            AccountConfigDetailResponse detail = convertToDetailResponse(config);
            return objectMapper.writeValueAsString(detail);
        } catch (Exception e) {
            log.warn("序列化账号配置失败: {}", e.getMessage());
            return "{}";
        }
    }

    private void recordAccountConfigHistory(Integer accountConfigId,
                                            String oldConfigJson,
                                            String newConfigJson,
                                            String summary,
                                            String operationType) {
        AccountConfigHistory history = new AccountConfigHistory();
        history.setAccountConfigId(accountConfigId);
        history.setOldConfig(StringUtils.hasText(oldConfigJson) ? oldConfigJson : "{}");
        history.setNewConfig(StringUtils.hasText(newConfigJson) ? newConfigJson : "{}");
        history.setChangeSummary(StringUtils.hasText(summary) ? summary : "配置变更");
        history.setOperationType(operationType);
        accountConfigHistoryRepository.save(history);
    }

    private AccountConfigHistoryResponse convertToHistoryResponse(AccountConfigHistory history) {
        AccountConfigHistoryResponse response = new AccountConfigHistoryResponse();
        response.setId(history.getId());
        response.setAccountConfigId(history.getAccountConfigId());
        response.setOldConfig(history.getOldConfig());
        response.setNewConfig(history.getNewConfig());
        response.setChangeSummary(history.getChangeSummary());
        response.setOperationType(history.getOperationType());
        response.setCreatedAt(history.getCreatedAt());
        return response;
    }

    /**
     * 应用覆盖配置
     */
    private void applyOverrides(AccountConfig config, Map<String, Object> overrides) {
        if (overrides.containsKey("buyAmount")) {
            Object buyAmountObj = overrides.get("buyAmount");
            if (buyAmountObj instanceof Number) {
                config.setBuyAmount(BigDecimal.valueOf(((Number) buyAmountObj).doubleValue()));
            }
        }
        if (overrides.containsKey("targetBuyQuote")) {
            Object targetQuoteObj = overrides.get("targetBuyQuote");
            if (targetQuoteObj instanceof Number) {
                config.setTargetBuyQuote(BigDecimal.valueOf(((Number) targetQuoteObj).doubleValue()));
            }
        }
        if (overrides.containsKey("proxyEnabled")) {
            Object proxyObj = overrides.get("proxyEnabled");
            if (proxyObj instanceof Boolean) {
                config.setProxyEnabled(((Boolean) proxyObj) ? 1 : 0);
            }
        }
        if (overrides.containsKey("customConfig")) {
            try {
                Object customConfigObj = overrides.get("customConfig");
                String customConfigJson = objectMapper.writeValueAsString(customConfigObj);
                config.setCustomConfig(customConfigJson);
            } catch (Exception e) {
                log.warn("处理自定义配置覆盖失败: {}", e.getMessage());
            }
        }
    }

    /**
     * 转换为列表响应
     */
    private AccountConfigListResponse convertToListResponse(AccountConfig config) {
        AccountConfigListResponse response = new AccountConfigListResponse();
        response.setId(config.getId());
        response.setAccountId(config.getAccountId());
        response.setConfigName(config.getConfigName());
        response.setProjectName(config.getProjectName());
        response.setBaseAsset(config.getBaseAsset());
        response.setQuoteAsset(config.getQuoteAsset());
        response.setBuyAmount(config.getBuyAmount());
        response.setIsActive(config.getIsActive());
        response.setStatus(config.getStatus());
        response.setUpdatedAt(config.getUpdatedAt());
        return response;
    }

    /**
     * 转换为详情响应
     */
    private AccountConfigDetailResponse convertToDetailResponse(AccountConfig config) {
        AccountConfigDetailResponse response = new AccountConfigDetailResponse();
        response.setId(config.getId());
        response.setAccountId(config.getAccountId());
        response.setConfigName(config.getConfigName());
        response.setProjectName(config.getProjectName());
        response.setBaseAsset(config.getBaseAsset());
        response.setQuoteAsset(config.getQuoteAsset());
        response.setChainId(config.getChainId());
        response.setContractAddress(config.getContractAddress());
        response.setBuyAmount(config.getBuyAmount());
        response.setTargetBuyQuote(config.getTargetBuyQuote());
        response.setProxyEnabled(config.getProxyEnabled() == 1);
        response.setProxyConfig(config.getProxyConfig());
        response.setNotifyUrl(config.getNotifyUrl());
        response.setCustomConfig(config.getCustomConfig());
        response.setRemark(config.getRemark());
        response.setIsActive(config.getIsActive());
        response.setStatus(config.getStatus());
        response.setCreatedAt(config.getCreatedAt());
        response.setUpdatedAt(config.getUpdatedAt());
        return response;
    }
}
